package init

import (
	"cogpt/internal/config"
	"cogpt/internal/log"
	"cogpt/internal/proxy"
	"flag"
	"fmt"
	"github.com/joho/godotenv"
	"os"
	"strconv"
	"strings"
)

func initConfigInstance() {
	config.ConfigInstance.Host = config.DefaultHost
	config.ConfigInstance.Port = config.DefaultPort
	config.ConfigInstance.Cache = config.DefaultCache
	config.ConfigInstance.CachePath = config.DefaultCachePath
	config.ConfigInstance.Debug = config.DefaultDebug
	config.ConfigInstance.LogLevel = "disabled"
	config.ConfigInstance.ShareToken = make(map[string]string)
	config.ConfigInstance.Proxy = config.DefaultProxy
}

func initConfigEnv() {
	if _, err := os.Stat(".env"); err == nil {
		err := godotenv.Load()
		if err != nil {
			panic(err)
		}
	}

	log.Logger.Info().Str("type", "initConfigEnv").Msg("Loaded .env file")
}

func initConfig() {
	parseFlags(&config.ConfigInstance)

	log.Logger.Info().Str("type", "initConfig").Msg("Initialized config")
}

func parseFlags(configInstance *config.Config) {
	var shareTokenStr string

	flag.StringVar(&configInstance.Host, "host", getEnvOrDefault("HOST", config.DefaultHost), "Host to listen on")
	flag.IntVar(&configInstance.Port, "port", getEnvOrDefaultPort("PORT", config.DefaultPort), "Port to listen on")
	flag.BoolVar(&configInstance.Cache, "cache", getEnvOrDefaultBool("CACHE", config.DefaultCache), "Enable cache")
	flag.StringVar(&configInstance.CachePath, "cache-path", getEnvOrDefault("CACHE_PATH", config.DefaultCachePath), "Path to the persistent cache")
	flag.BoolVar(&configInstance.Debug, "debug", getEnvOrDefaultBool("DEBUG", config.DefaultDebug), "Enable debug mode, if enabled, more information will be outputed")
	flag.StringVar(&config.ConfigInstance.LogLevel, "log-level", getEnvOrDefault("LOG_LEVEL", config.DefaultLogLevel), "Log level")
	flag.StringVar(&shareTokenStr, "share-token", config.DefaultShareTokenStr, "Share token, format: <token>:<model>,<token>:<model>,...")
	flag.StringVar(&config.ConfigInstance.Proxy, "proxy", proxy.GetEnvProxyAddress(), "Proxy address, format: scheme://host:port, e.g. http://localhost:7890 or socks5://localhost:7890")

	flag.Parse()

	configInstance.ShareToken = parseShareTokenOrDefault(shareTokenStr, "SHARE_TOKEN")
}

func getEnvOrDefault(key, defaultValue string) string {
	value := os.Getenv(key)
	if value == "" {
		return defaultValue
	}
	return value
}

func getEnvOrDefaultPort(key string, defaultValue int) int {
	value := os.Getenv(key)
	if value == "" {
		return defaultValue
	}
	s, err := strconv.Atoi(value)
	if err != nil || s < 0 || s > 65535 {
		fmt.Println("invalid port number, using default port:", defaultValue)
		return defaultValue
	}
	return s
}

func getEnvOrDefaultBool(key string, defaultValue bool) bool {
	value := os.Getenv(key)
	if value == "" {
		return defaultValue
	}
	s, err := strconv.ParseBool(value)
	if err != nil {
		fmt.Println("invalid boolean value, using default value:", defaultValue)
		return defaultValue
	}
	return s
}

func parseShareTokenOrDefault(shareTokenStr string, key string) map[string]string {
	if shareTokenStr == "" {
		shareTokenStr = os.Getenv(key)
	}
	if shareTokenStr == "" {
		return map[string]string{}
	}
	s := strings.Split(shareTokenStr, ",")
	shareToken := map[string]string{}
	for _, v := range s {
		// split by colon
		ss := strings.Split(v, ":")

		// format check
		if len(ss) != 2 {
			fmt.Printf("invalid share token mapping: %s, skip\n", v)
			continue
		}
		if !strings.HasPrefix(ss[0], "share-") || !strings.HasPrefix(ss[1], "ghu_") {
			log.Logger.Warn().Str("type", "parseShareTokenOrDefault").Msgf("invalid share token mapping: %s, skip", v)
			continue
		}

		shareToken[ss[0]] = ss[1]
	}
	return shareToken
}
